#!/usr/bin/env python
# encoding: utf-8
'''
@author: DeltaF
@software: pycharm
@file: strategy.py
@time: 2021/3/5 19:18
@desc: 用来创建交易策略、生成交易信号
'''

import data.stock as st
import numpy as np
import datetime
import matplotlib.pyplot as plt
import pandas as pd
from normal import sf_time


def compose_signal(data):
    """
    整合型号
    :param data:
    :return:
    """
    data['buy_signal'] = np.where((data['buy_signal'] == 1) & (data['buy_signal'].shift(1) == 1)
                                  , 0, data['buy_signal'])

    data['sell_signal'] = np.where((data['sell_signal'] == -1) & (data['sell_signal'].shift(1) == -1)
                                   , 1, data['sell_signal'])

    data['signal'] = data['buy_signal'] + data['sell_signal']
    return data


def calculate_sharpe(data):
    """
    夏普比例：衡量资产相对无风险表现情况，夏普比例大于1这说明资产更容易赚钱，回撤小收益高
    :param data:
    :return:
    """
    # 公式：sharpe = (回报率的均值 - 无风险利率) / 回报率的标准差
    daily_return = data['close'].pct_change()  # pct_change 计算每天的涨跌幅
    avg_return = daily_return.mean()
    sd_return = daily_return.std()
    # 计算夏普：每日收益率 * 252 = 每年收益率
    sharpe = avg_return / sd_return
    sharpe_year = sharpe * np.sqrt(252)
    print(sharpe_year)
    return sharpe, sharpe_year


def calculate_max_drawdown(data):
    """
    计算最大回撤比
    :param data:
    :return:
    """
    # 选取时间周期（时间窗口）
    window = 252
    # 选取时间周期中的最大净值
    data['roll_max'] = data['close'].rolling(window=window, min_periods=1).max()
    # 计算当天的回撤比 = (谷值 — 峰值)/峰值 = 谷值/峰值 - 1
    data['daily_dd'] = data['close'] / data['roll_max'] - 1
    # 选取时间周期内最大的回撤比，即最大回撤
    data['max_dd'] = data['daily_dd'].rolling(window, min_periods=1).min()
    return data


def calculate_prof_pct(data):
    """
    计算单次收益率：开仓，平仓（开仓的全部股数）
    :param data:
    :return:
    """
    # 筛选信号不为0的， 并且计算涨跌幅
    data.loc[data['signal'] != 0, 'profit_pct'] = data['close'].pct_change()
    # 筛选平仓的数据：单次收益
    data = data[data['signal'] == -1]
    return data


def calculate_cum_prof(data):
    """
    计算累计收益率
    :param data: dataframe
    :return:
    """
    # 累计收益
    data['cum_profit'] = pd.DataFrame(1 + data['profit_pct']).cumprod() - 1
    return data


def calculate_portfolio_return(data, signal, n):
    """
    计算组合收益率
    :param data: dataframe
    :param signal: dataframe
    :param n: int
    :return: dataframe
    """
    returns = data.copy()
    # 组合收益率 (等权重) = 收益率之和 / 股票个数
    returns['profit_pct'] = (signal * returns.shift(-1)).T.sum() / n
    returns = calculate_cum_prof(returns)
    return returns.shift(1) # 匹配对应交易月份






def test_caculate_max_drawdown():
    # df = st.get_single_price('300458.XSHE', 'daily', '2021-06-01', '2021-09-01')
    # df = calculate_max_drawdown(df)
    # max_dd = df['max_dd'].min()
    # first = df.loc[df.index.min()]
    # last = df.loc[df.index.max()]
    #
    # print(df[['close', 'roll_max', 'daily_dd', 'max_dd']])
    # print(max_dd)
    # print(first)
    # print(last)
    # print(df.index.max())
    # 全志科技，健帆生物，中顺结柔，智飞生物
    # code_list = ['300458.XSHE', '300529.XSHE', '002511.XSHE', '300122.XSHE']
    code_list = ['300122.XSHE']
    for code in code_list:
        df = st.get_single_price(code, 'daily', '2015-01-01', datetime.datetime.today())
        df = calculate_max_drawdown(df)
        max_dd = df['max_dd'].min() * 100  # 在上面给点时间段的最大回撤
        df[['daily_dd', 'max_dd']].plot()
        plt.show()


def test_calculate_sharpe():
    """
    测试夏普值
    :return:
    """
    # 智飞生物
    df = st.get_single_price('300122.XSHE', 'daily', '2021-01-01', datetime.datetime.today())
    calculate_sharpe(df)


def test_where():
    """
    测试排序
    :return:
    """
    # 智飞生物 时间格式  '2021-01-01'
    lastMoth = sf_time.getdate(30)
    df = st.get_single_price('300122.XSHE', 'daily', lastMoth, datetime.datetime.today())
    # 默认升序排列
    df = df.sort_values('close')
    # 最近一个月最低收盘值
    print(df.head(1))
    # 最近一个月最大收盘值
    print(df.tail(1))
    # 收盘价格小于150的有几天
    df = df[df['close'] < 150]
    print(df.count())


def test_daily_where():
    """
    按照日期查询收盘价
    :return:
    """
    lastMoth = sf_time.getdate(30)
    df = st.get_single_price('300122.XSHE', 'daily', lastMoth, datetime.datetime.today())

    # 设置索引列名为 date
    df.index.names = ['date']
    print(df)
    # 按照日期查询收盘价
    daily = df[df.index == '2021-09-07']['close']
    print(daily)


if __name__ == '__main__':
    # test_caculate_max_drawdown()
    # test_calculate_sharpe()
    test_where()
    data = [100, 93, 86, ]
